package dxsvalue

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"github.com/suiyunonghen/DxCommonLib"
	"io"
	"time"
	"unsafe"
)

type MsgPackReader struct {
	bfReader		*bufio.Reader
}

func NewMsgPackReader(r io.Reader)MsgPackReader  {
	var result MsgPackReader
	if bfReader,ok := r.(*bufio.Reader);ok{
		result.bfReader = bfReader
	}else{
		result.bfReader = bufio.NewReader(r)
	}
	return result
}

func (r *MsgPackReader)Reset(reader io.Reader)  {
	if bfReader,ok := reader.(*bufio.Reader);ok{
		r.bfReader = bfReader
	}else{
		r.bfReader = bufio.NewReader(reader)
	}
}

func (r *MsgPackReader)readCode()(MsgPackCode,error)  {
	b,err := r.bfReader.Peek(1)
	if err != nil{
		return CodeUnkonw, err
	}
	r.bfReader.Discard(1)
	return MsgPackCode(b[0]),nil
}

func (r *MsgPackReader)parseU8()(byte,error)  {
	b,err := r.bfReader.Peek(1)
	if err != nil{
		return 0, err
	}
	result := b[0]
	r.bfReader.Discard(1)
	return result, nil
}

func (r *MsgPackReader)parseU16()(uint16,error)  {
	b,err := r.bfReader.Peek(2)
	if err != nil{
		return 0, err
	}
	result := (uint16(b[0]) << 8) | uint16(b[1])
	r.bfReader.Discard(2)
	return result,nil
}

func (r *MsgPackReader)parseU32()(uint32,error)  {
	b,err := r.bfReader.Peek(4)
	if err != nil{
		return 0, err
	}
	result := (uint32(b[0]) << 24) | (uint32(b[1]) << 16) | (uint32(b[2]) << 8) | uint32(b[3])
	r.bfReader.Discard(4)
	return result,nil
}

func (r *MsgPackReader)parseU64()(uint64,error)  {
	b,err := r.bfReader.Peek(8)
	if err != nil{
		return 0, err
	}
	result := (uint64(b[0]) << 56) | (uint64(b[1]) << 48) | (uint64(b[2]) << 40) | (uint64(b[3]) << 32) |
		(uint64(b[4]) << 24) | (uint64(b[5]) << 16) | (uint64(b[6]) << 8) | uint64(b[7])
	r.bfReader.Discard(8)
	return result,nil
}


func (r *MsgPackReader) parseLen(code MsgPackCode)(int,error)  {
	if code.IsFixedStr(){
		return int(code & CodeFixedStrMask), nil
	}
	switch code {
	case CodeStr8, CodeBin8:
		codeLen,err := r.parseU8()
		if err != nil{
			return 0, err
		}
		return int(codeLen), nil
	case CodeStr16, CodeBin16:
		codeLen,err := r.parseU16()
		if err != nil{
			return 0, err
		}
		return int(codeLen), nil
	case CodeStr32, CodeBin32:
		codeLen,err := r.parseU32()
		if err != nil{
			return 0, err
		}
		return int(codeLen), nil
	}
	return 0,ErrParseObjLen
}

func (r *MsgPackReader) parseExtLen(code MsgPackCode)(int ,error)  {
	switch code {
	case CodeFixExt1:
		return 1,nil
	case CodeFixExt2:
		return 2,nil
	case CodeFixExt4:
		return 4,nil
	case CodeFixExt8:
		return 8,nil
	case CodeFixExt16:
		return 16,nil
	case CodeExt8:
		n,err := r.parseU8()
		return int(n),err
	case CodeExt16:
		n, err := r.parseU16()
		return int(n),err
	case CodeExt32:
		n,err := r.parseU32()
		return int(n),err
	default:
		return 0,fmt.Errorf("msgpack: invalid code=%x decoding ext length", code)
	}
}

func (r *MsgPackReader)parseString(code MsgPackCode)(result string,err error)  {
	stLen,err := r.parseLen(code)
	if err != nil{
		return "",ErrParseObjLen
	}
	if stLen <= 0 {
		return "", nil
	}
	b := make([]byte,stLen)
	l,err := r.bfReader.Read(b)
	if err != nil{
		return "", err
	}
	if l == stLen{
		return DxCommonLib.FastByte2String(b[:l]),nil
	}
	return "",fmt.Errorf("msgpack: string data truncated,totalen=%d,realLen=%d",stLen,l)
}

func (r *MsgPackReader)parseMsgPackValue(c *ValueCache)(*DxValue,error)  {
	code,err := r.readCode()
	if err != nil{
		return nil,err
	}
	switch  {
	case code.IsStr():
		strValue,err := r.parseString(code)
		if err != nil{
			return nil,err
		}
		result := c.getValue(VT_String)
		result.fstrvalue = strValue
		return result,nil
	case code.IsArray():
		return r.parseMsgPackArray(code,c)
	case code.IsMap():
		return r.parseMsgPackObject(code,c)
	case code.IsFixedNum():
		result := c.getValue(VT_Int)
		result.SetInt(int64(int8(code)))
		return result,nil
	case code == CodeUint8:
		u8,err := r.parseU8()
		if err != nil{
			return nil,err
		}
		result := c.getValue(VT_Int)
		result.SetInt(int64(u8))
		return result,nil
	case code == CodeInt8:
		b,err := r.bfReader.Peek(1)
		if err != nil{
			return nil, err
		}
		i8 := int8(b[0])
		r.bfReader.Discard(1)
		result := c.getValue(VT_Int)
		result.SetInt(int64(i8))
		return result,nil
	case code == CodeUint16:
		b,err := r.bfReader.Peek(2)
		if err != nil{
			return nil, err
		}
		u16 := (uint16(b[0]) << 8) | uint16(b[1])
		r.bfReader.Discard(2)

		result := c.getValue(VT_Int)
		result.SetInt(int64(u16))
		return result,nil
	case code == CodeInt16:
		b,err := r.bfReader.Peek(2)
		if err != nil{
			return nil, err
		}
		u16 := (uint16(b[0]) << 8) | uint16(b[1])
		r.bfReader.Discard(2)
		result := c.getValue(VT_Int)
		result.SetInt(int64(int16(u16)))
		return result,nil
	case code == CodeUint32:
		u32,err := r.parseU32()
		if err != nil{
			return nil,err
		}
		result := c.getValue(VT_Int)
		result.SetInt(int64(u32))
		return result,nil
	case code == CodeInt32:
		u32,err := r.parseU32()
		if err != nil{
			return nil,err
		}
		result := c.getValue(VT_Int)
		result.SetInt(int64(int32(u32)))
		return result,nil
	case code == CodeInt64 || code == CodeUint64:
		u64,err := r.parseU64()
		if err != nil{
			return nil,err
		}
		result := c.getValue(VT_Int)
		result.SetInt(int64(u64))
		return result,nil
	case code == CodeFloat:
		u32,err := r.parseU32()
		if err != nil{
			return nil,err
		}
		result := c.getValue(VT_Float)
		result.SetFloat(*(*float32)(unsafe.Pointer(&u32)))
		return result,nil
	case code == CodeDouble:
		u64,err := r.parseU64()
		if err != nil{
			return nil,err
		}
		result := c.getValue(VT_Double)
		result.SetDouble(*(*float64)(unsafe.Pointer(&u64)))
		return result,nil
	case code == CodeTrue:
		return valueTrue,nil
	case code == CodeFalse:
		return valueFalse,nil
	case code == CodeNil:
		return valueNull,nil
	case code.IsBin():
		//二进制
		blen,err := r.parseLen(code)
		if err != nil{
			return nil,err
		}
		b := make([]byte,blen)
		haslen,err := r.bfReader.Read(b)
		if err != nil{
			return nil, err
		}
		if blen == haslen{
			result := c.getValue(VT_Binary)
			result.fbinary = b[:haslen]
			return result,nil
		}
		return nil,fmt.Errorf("msgpack: binay data truncated,totalen=%d,realLen=%d",blen,haslen)
	case code.IsExt():
		//扩展，需要判定一下这个扩展是否是日期时间格式
		exlen,err := r.parseExtLen(code)
		if err != nil{
			return nil,err
		}
		//有一个类型
		b := make([]byte,exlen+1)
		haslen,err := r.bfReader.Read(b)
		if haslen < exlen{
			return nil, fmt.Errorf("msgpack: binay data truncated,totalen=%d,realLen=%d",exlen,haslen)
		}
		if code.IsTime(b[0]){
			//日期时间
			result := c.getValue(VT_DateTime)
			switch code {
			case CodeFixExt4:
				sec := binary.BigEndian.Uint32(b[1:])
				result.SetTime(time.Unix(int64(sec), 0))
			case CodeFixExt8:
				//64位时间格式
				sec := binary.BigEndian.Uint64(b[1:])
				nsec := int64(sec >> 34)
				sec &= 0x00000003ffffffff
				result.SetTime(time.Unix(int64(sec), nsec))
			default:
				nsec := binary.BigEndian.Uint32(b[1:])
				sec := binary.BigEndian.Uint64(b[5:])
				result.SetTime(time.Unix(int64(sec), int64(nsec)))
			}
			return result,nil
		}else{
			result := c.getValue(VT_ExBinary)
			result.fbinary = b[:exlen+1]
			return result,nil
		}
	}
	return nil, ErrInvalidateCode
}

func (r *MsgPackReader) parseArrLen(code MsgPackCode)(int ,error)  {
	if code >= CodeFixedArrayLow && code <= CodeFixedArrayHigh {
		return int(code & CodeFixedArrayMask), nil
	}
	switch code {
	case CodeArray16:
		n,err := r.parseU16()
		return int(n),err
	case CodeArray32:
		n,err := r.parseU32()
		return int(n),err
	}
	return 0,ErrInvalidateCode
}

func (r *MsgPackReader) parseMapLen(code MsgPackCode)(int,error)  {
	if code >= CodeFixedMapLow && code <= CodeFixedMapHigh {
		return int(code & CodeFixedMapMask), nil
	}
	switch code {
	case CodeMap16:
		u16,err := r.parseU16()
		if err != nil{
			err = ErrParseObjLen
		}
		return int(u16),err
	case CodeMap32:
		u32,err := r.parseU32()
		if err != nil{
			err = ErrParseObjLen
		}
		return int(u32),err
	}
	return 0,ErrInvalidateCode
}

func (r *MsgPackReader) parseMsgPackObject(code MsgPackCode,c *ValueCache)(result *DxValue,err error)  {
	maplen,err := r.parseMapLen(code)
	if err != nil{
		return nil,err
	}
	if maplen == 0{
		return c.getValue(VT_Object),nil
	}
	bt,err := r.bfReader.Peek(1)
	if err != nil{
		return nil, err
	}
	if !MsgPackCode(bt[0]).IsStr(){
		return nil,ErrMapKey
	}

	var key string
	var value *DxValue
	result = c.getValue(VT_Object)
	if c == nil{
		c = result.ValueCache()
	}
	for i := 0;i<maplen;i++{
		code,err = r.readCode()
		if err != nil{
			FreeValue(result)
			return nil,err
		}
		key,err = r.parseString(code)
		if err != nil{
			FreeValue(result)
			return nil,err
		}
		value,err = r.parseMsgPackValue(c)
		if err != nil{
			FreeValue(result)
			return nil,err
		}
		result.SetKeyValue(key,value)
	}
	return
}

func (r *MsgPackReader) parseMsgPackArray(code MsgPackCode,c *ValueCache)(result *DxValue,err error){
	arrlen,err := r.parseArrLen(code)
	if err != nil{
		return nil,err
	}
	if arrlen == 0{
		return c.getValue(VT_Array),nil
	}
	var value *DxValue
	result = c.getValue(VT_Array)
	if c == nil{
		c = result.ValueCache()
	}
	for i := 0;i<arrlen;i++{
		value,err = r.parseMsgPackValue(c)
		if err != nil{
			FreeValue(result)
			return nil,err
		}
		result.farr = append(result.farr,value)
	}
	return result,err
}

func (r *MsgPackReader) Decode()(*DxValue,error) {
	return r.parseMsgPackValue(getCache())
}
